﻿using System;
using System.Collections;
using System.Collections.Generic;
using Adaptive.Foundation.Tokenizers;

namespace Adaptive.Foundation.Parsing
{
    /// <summary>
    /// Provides a custom collection definition for storing <see cref="ParsingTokenRule"/> types.
    /// </summary>
    public sealed class ParsingTokenRuleCollection : GenericCollectionBase<ParsingTokenRule>
    {
        /*--------------------------------------------------------------------------------
         * Private Member Declarations
         *------------------------------------------------------------------------------*/
        #region Private Member Declarations
        /// <summary>
        /// Table containing token pattern strings.
        /// </summary>
        private Hashtable _patternTable;
        /// <summary>
        /// List of token pattern strings.
        /// </summary>
        private List<String> _patternList;
        #endregion

        /*--------------------------------------------------------------------------------
         * Constructor / Dispose Methods
         *------------------------------------------------------------------------------*/
        #region Constructor / Dispose Methods
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <remarks>
        /// This is the default constructor.
        /// </remarks>
        public ParsingTokenRuleCollection()
            : base()
        {
            _patternTable = new Hashtable();
            _patternList = new List<string>();
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Protected Methods
         *------------------------------------------------------------------------------*/
        #region Protected Methods
        /// <summary>
        /// Provides a the reference key value for adding the item to the internal reference
        /// key list.
        /// </summary>
        /// <param name="newObjectToBeAdded">The object to be added to the collecton.</param>
        /// <returns>
        /// A reference key used to identify the instance.
        /// </returns>
        protected override string GetKeyForObject(ParsingTokenRule newObjectToBeAdded)
        {
            return newObjectToBeAdded.Name;
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Public Methods / Functions
        /// <summary>
        /// Initializes the internal token pattern strings from the current object contents.
        /// </summary>
        public void InitPatternList()
        {
            int count = 0;                      //Iteration counter.
            int length = 0;                     //Iteration limit.
            string pattern = string.Empty;      //New pattern string.

            length = Count;
            _patternList.Clear();
            _patternTable.Clear();

            for (count = 0; count < length; count++)
            {
                if ((this[count].TokenList != null) && (this[count].TokenList.Count > 0))
                {
                    pattern = string.Empty;
                    foreach (RawToken token in this[count].TokenList)
                    {
                        pattern += token.TokenValue;
                    }
                    _patternTable.Add(pattern, this[count]);
                    _patternList.Add(pattern);
                }
            }
        }
        /// <summary>
        /// Determines if the token list matches a rule pattern.
        /// </summary>
        /// <param name="list">
        /// A <see cref="RawTokenCollection"/> containing a list of tokens.
        /// </param>
        /// <returns>
        /// <b>true</b> if the list matches one of the <see cref="ParsingTokenRule.TokenList"/>
        /// collections; otherwise, returns <b>false</b>.
        /// </returns>
        public bool PatternMatch(RawTokenCollection list)
        {
            return (_patternTable[GetPatternText(list)] != null);
        }
        /// <summary>
        /// Gets the parsing rule for the provided token list.
        /// </summary>
        /// <param name="list">
        /// A <see cref="RawTokenCollection"/> containing a list of tokens.
        /// </param>
        /// <returns>
        /// The <see cref="ParsingTokenRule"/> whose token list contenst match that
        /// of the <i>list</i> collection exactly.
        /// </returns>
        public ParsingTokenRule GetPatternRuleForList(RawTokenCollection list)
        {
            return (ParsingTokenRule)_patternTable[GetPatternText(list)];
        }
        /// <summary>
        /// Gets the rule for the provided token.
        /// </summary>
        /// <param name="token">
        /// The token to get a parsing rule for.
        /// </param>
        /// <returns>
        /// The <see cref="ParsingTokenRule"/> instance assigned to the token; otherwise,
        /// returns <b>null</b>.
        /// </returns>
        public ParsingTokenRule GetRuleForToken(RawToken token)
        {
            int count = 0;                                  //Iteration counter.
            int length = 0;                                 //Iteration limit.
            ParsingTokenRule returnValue = null;            //Return value.

            length = Count;
            count = 0;
            do
            {
                if (this[count].Token != null)
                {
                    if (this[count].Token.TokenValue == token.TokenValue)
                        returnValue = this[count];
                }
                count++;
            } while ((count < length) && (returnValue == null));

            return returnValue;
        }
        /// <summary>
        /// Determines whether a contained rule's token list contains the provided
        /// token list.
        /// </summary>
        /// <param name="list">
        /// A <see cref="RawTokenCollection"/> containing a list of tokens.
        /// </param>
        /// <returns>
        /// <b>true</b> if <i>list</i> indicates a pattern in a rule; otherwise,
        /// <b>false</b>.
        /// </returns>
        public bool IsInPattern(RawTokenCollection list)
        {
            string data = GetPatternText(list);
            bool returnValue = false;
            int count = 0;

            for (count = 0; count < _patternList.Count; count++)
            {
                returnValue = (_patternList[count].IndexOf(data) > -1);
            }
            return returnValue;
        }
        /// <summary>
        /// Translates the list into a string pattern.
        /// </summary>
        /// <param name="list">
        /// A <see cref="RawTokenCollection"/> containing a list of tokens.
        /// </param>
        /// <returns>
        /// The string pattern for the providedlist.
        /// </returns>
        public string GetPatternText(RawTokenCollection list)
        {
            string returnValue = string.Empty;
            
            foreach (RawToken token in list)
            {
                returnValue += token.TokenValue;
            }
            return returnValue;
        }
        /// <summary>
        /// Determines whether a rule exists for the specified token.
        /// </summary>
        /// <param name="token">
        /// The token to get a parsing rule for.
        /// </param>
        /// <returns>
        /// <b>true</b> if a parsing rule exists for the specified token; 
        /// otherwise, <b>false</b>.
        /// </returns>
        public bool IsRuleForToken(RawToken token)
        {
            int count = 0;                      // Iteration counter.
            int length = 0;                     // Iteration limit.
            bool returnValue = false;           // Return value.

            if (token != null)
            {
                length = Count;
                count = 0;
                do
                {
                    if (this[count].Token != null)
                    {
                        returnValue = (this[count].Token.TokenValue == token.TokenValue);
                    }
                    count++;
                } while ((count < length) && (!returnValue));
            }
            return returnValue;
        }
        /// <summary>
        /// Determines whether the specified token is present in any rule's Token list.
        /// </summary>
        /// <param name="token">
        /// The token to locate in a rule pattern.
        /// </param>
        /// <returns>
        /// <b>true</b> if any rule pattern starts with the specified token;
        /// otherwise, <b>false</b>.
        /// </returns>
        public bool IsTokenInRulePatternStart(RawToken token)
        {
            int count = 0;
            int length = 0;
            bool returnValue = false;

            length = Count;
            count = 0;
            do
            {
                if ((this[count].TokenList != null) && (this[count].TokenList.Count > 0))
                {
                    if (token != null)
                        returnValue = (this[count].TokenList[0].TokenValue == token.TokenValue);
                }
                count++;
            } while ((count < length) && (!returnValue));

            return returnValue;
        }        
        #endregion
    }
}